home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume91 / utilitys / browser1 / part01
Encoding:
Internet Message Format  |  1991-03-25  |  34.8 KB

  1. Path: news.larc.nasa.gov!amiga-request
  2. From: amiga-request@ab20.larc.nasa.gov (Amiga Sources/Binaries Moderator)
  3. Subject: v91i074: Browser 1.7 - a programmer's "Workbench", Part01/01
  4. Reply-To: peter@taronga.hackercorp.com
  5. Newsgroups: comp.sources.amiga
  6. Message-ID: <comp.sources.amiga:v91i074@ab20.larc.nasa.gov>
  7. Date: 25 Mar 91 15:44:34 GMT
  8. Approved: tadguy@uunet.UU.NET (Tad Guy)
  9. X-Mail-Submissions-To: amiga@uunet.uu.net
  10. X-Post-Discussions-To: comp.sys.amiga.misc
  11.  
  12. Submitted-by: peter@taronga.hackercorp.com
  13. Posting-number: Volume 91, Issue 074
  14. Archive-name: utilities/browser-1.7/part01
  15.  
  16. Well, 1.4 is now 2.0, and it's almost here. So this is probably going to
  17. be the last revision of Browser. I'm now using Workbench 2.0 on a daily
  18. basis, and I find I'm not using Browser that much. It remains faster than
  19. workbench and cleaner for quick jobs, but not enough for me to spend much
  20. time on it. However, lots of people remain in a 1.3 environment, and with
  21. the new release of the Aztec C compiler (5.0d) I've been able to clear up
  22. several outstanding bugs in Browser. Thus, the new release.
  23.  
  24.     What Browser does allow you to do, easily and conveniently, is to
  25. move, copy, rename, and delete files and directories. It will also let you
  26. execute either Workbench or CLI programs, either directly by double-
  27. clicking them or by selecting them from a menu. By combining these you can
  28. set up a complete operating environment that will, to a large extent,
  29. replace both Workbench and the CLI.
  30.  
  31. #!/bin/sh
  32. # This is a shell archive.  Remove anything before this line, then unpack
  33. # it by saving it into a file and typing "sh file".  To overwrite existing
  34. # files, type "sh file -c".  You can also feed this as standard input via
  35. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  36. # will see the following message at the end:
  37. #        "End of archive 1 (of 1)."
  38. # Contents:  PatMatch.c browser.doc fonts.h goodies.readme menu.c
  39. #   menu.h vollist.c
  40. # Wrapped by tadguy@ab20 on Mon Mar 25 10:44:32 1991
  41. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  42. if test -f 'PatMatch.c' -a "${1}" != "-c" ; then 
  43.   echo shar: Will not clobber existing file \"'PatMatch.c'\"
  44. else
  45. echo shar: Extracting \"'PatMatch.c'\" \(5837 characters\)
  46. sed "s/^X//" >'PatMatch.c' <<'END_OF_FILE'
  47. X/* PatMatch.c - Implements AmigaDos Regular Expression Pattern Matching.
  48. X**
  49. X**  This program will test whether a string is an AmigaDos  regular expression
  50. X**  It may be used to implement wild expressions such as:
  51. X**
  52. X**    "copy #?.c to <dir>" to copy any file ending in .c
  53. X**
  54. X**  The program has two entry points: CmplPat, and Match.
  55. X**
  56. X**    CmplPat - takes a pattern and returns an auxilliary integer vector
  57. X**              which is used by Match.  The pattern is not modified in
  58. X**              any way.  CmplPat returns 1 if no errors were detected
  59. X**              while compiling the pattern; otherwise it returns 0;
  60. X**
  61. X**    Match   - takes the pattern, the auxilliary vector, and the string
  62. X**              to be matched.  It returns 1 if the string matches the
  63. X**              pattern; otherwise it returns 0;
  64. X**
  65. X**  Translated from BCPL by:
  66. X**              Jeff Lydiatt
  67. X**              Richmond B.C. Canada
  68. X**              16 May 1986.
  69. X**
  70. X**  Source: "A Compact Function for Regular Expression Pattern Matching",
  71. X**           Software - Practice and Experience, September 1979.
  72. X**
  73. X**  Useage:
  74. X**     To test if "file.c" matches the regular expression "#?.c"
  75. X**     char *Pat = "#?.c";
  76. X**     char *Str = "file.c";
  77. X**     WORD Aux[128];
  78. X**
  79. X**     if ( CmplPat( Pat, Aux ) == 0 )
  80. X**        {
  81. X**           printf("Bad Wildcard Expression\n");
  82. X**           exit(1);
  83. X**        }
  84. X**     if ( Match( Pat, Aux, Str ) == 1 )
  85. X**        printf("String matches the pattern\n");
  86. X**     else
  87. X**        printf("String does NOT match the pattern\n");
  88. X**/
  89. X
  90. X/*--- Included files ----*/
  91. X
  92. X#include <stdio.h>
  93. X#include <exec/types.h>
  94. X#include <ctype.h>
  95. X
  96. X#define  EOS '\0'
  97. X
  98. X/*--- Global Variables  ---*/
  99. X
  100. Xstatic char     Ch;      /* The current character in Pattern */
  101. Xstatic char     *Pat;    /* Pointer to the Pattern */
  102. Xstatic WORD     *Aux;    /* Pointer to returned auxilliary vector */
  103. Xstatic int      PatP;    /* Current position in Pat */
  104. Xstatic int      Patlen;  /* strlen(pat) */
  105. Xstatic BOOL     Errflag; /* TRUE if error */
  106. Xstatic WORD     *Work;   /* Pointer to Active work area */
  107. Xstatic int      Wp;      /* Current position in work */
  108. Xstatic BOOL     Succflag;/* True if "str" matches "pat" */
  109. X
  110. X/*----------------------------------------------------------------*/
  111. X/*                   The Interpreter                              */
  112. X/*----------------------------------------------------------------*/
  113. X
  114. Xstatic void Put(int N)
  115. X{
  116. X   register WORD *ip;
  117. X   register WORD *to;
  118. X
  119. X   if ( N == 0 )
  120. X      Succflag = TRUE;
  121. X   else
  122. X      {
  123. X    for ( ip = &Work[ 1 ], to = &Work[ Wp ]; ip <= to; ip++)
  124. X       if ( *ip == N )
  125. X          return;
  126. X    Work[ ++Wp ] = N;
  127. X      }
  128. X}
  129. X
  130. Xint Match( char *Pat, WORD *Aux, char *Str )
  131. X{
  132. X   static WORD W[ 128 ];
  133. X   int  S = 0;
  134. X   int  I, N, Q, P, Strlength;
  135. X   char K;
  136. X   int  strlen();
  137. X   void Put();
  138. X
  139. X   Work = W;
  140. X   Wp = 0;
  141. X   Succflag = FALSE;
  142. X   Strlength = strlen( Str );
  143. X   Put( 1 );
  144. X
  145. X   if ( Aux[ 0 ] != 0 )
  146. X      Put( Aux[ 0 ] );
  147. X
  148. X   for(;;)
  149. X      {
  150. X        /* First complete the closure */
  151. X        for( N=1; N <= Wp; N++ )
  152. X          {
  153. X         P = Work[ N ];
  154. X         K = Pat[ P-1 ];
  155. X         Q = Aux[ P ];
  156. X         switch( K )
  157. X           {
  158. X          case '#': Put( P + 1 );
  159. X          case '%': Put( Q );
  160. X          default : break;
  161. X          case '(':
  162. X          case '|': Put( P + 1);
  163. X                if ( Q != 0 )
  164. X                   Put( Q );
  165. X        }
  166. X       }
  167. X
  168. X    if ( S >= Strlength )
  169. X       return Succflag;
  170. X    if ( Wp == 0 )
  171. X       return FALSE;
  172. X    Ch = Str[ S++ ];
  173. X
  174. X    /* Now deal with the match items */
  175. X
  176. X    N = Wp;
  177. X    Wp = 0;
  178. X    Succflag = FALSE;
  179. X
  180. X    for ( I = 1; I <= N; I++)
  181. X      {
  182. X         P = Work[ I ];
  183. X         K = Pat[ P - 1 ];
  184. X         switch( K )
  185. X           {
  186. X         case '#':
  187. X         case '|':
  188. X         case '%':
  189. X         case '(': break;
  190. X         case '\'': K = Pat[ P ];
  191. X         default : if ( _toupper( Ch ) != _toupper( K ) )
  192. X                  break;
  193. X         case '?': /* Successful match */
  194. X                Put ( Aux[ P ] );
  195. X        } /* End Switch */
  196. X      } /* End For I */
  197. X     } /* End for(;;) */
  198. X}
  199. X
  200. X
  201. X/*----------------------------------------------------------------*/
  202. X/*                     The Compiler                               */
  203. X/*----------------------------------------------------------------*/
  204. X
  205. Xstatic void  Rch(void) /* Read next character from Pat */
  206. X{
  207. X   if ( PatP >= Patlen )
  208. X      Ch = EOS;
  209. X   else
  210. X      Ch = Pat[ PatP++ ];
  211. X}
  212. X
  213. Xstatic void Nextitem(void) /* Get next char from Pat; recognize the ' escape char */
  214. X{
  215. X   if ( Ch == '\'' )
  216. X      Rch();
  217. X   Rch();
  218. X}
  219. X
  220. Xstatic void Setexits( int List, int Val )
  221. X{
  222. X   int A;
  223. X
  224. X   do
  225. X     {
  226. X    A = Aux[ List ];
  227. X    Aux[ List ] = Val;
  228. X    List = A;
  229. X     }
  230. X    while ( List != 0 );
  231. X}
  232. X
  233. Xstatic int Join( int A, int B )
  234. X{
  235. X    int T = A;
  236. X
  237. X    if ( A == 0 )
  238. X    return B;
  239. X    while ( Aux[ A ] != 0 )
  240. X    A = Aux[ A ];
  241. X    Aux[ A ] = B;
  242. X    return T;
  243. X}
  244. X
  245. Xstatic int Prim(void)      /* Parse a Prim symbol */
  246. X{
  247. X   int   A = PatP;
  248. X   char Op = Ch;
  249. X   int  Exp();
  250. X   void Setexits(), Nextitem();
  251. X
  252. X   Nextitem();
  253. X   switch( Op )
  254. X     {
  255. X        case EOS:
  256. X        case ')':
  257. X        case '|': Errflag = TRUE;
  258. X        default : return A;
  259. X        case '#': Setexits( Prim(), A ); return A;
  260. X        case '(': A = Exp( A );
  261. X          if ( Ch != ')' )
  262. X            {
  263. X            Errflag = TRUE;
  264. X            }
  265. X          Nextitem();
  266. X          return A;
  267. X     }
  268. X}
  269. X
  270. Xstatic int Exp( int AltP )    /* Parse an expression */
  271. X{
  272. X   int Exits = 0;
  273. X   int A;
  274. X   int Prim(), Exits(), Join();
  275. X   void Nextitem(), Setexits();
  276. X
  277. X   for (;;)
  278. X    {
  279. X       A = Prim();
  280. X       if ( Ch == '|' || Ch == ')' || Ch == EOS )
  281. X          {
  282. X        Exits = Join( Exits, A );
  283. X        if ( Ch != '|' )
  284. X           return Exits;
  285. X        Aux[ AltP ] = PatP;
  286. X        AltP = PatP;
  287. X        Nextitem();
  288. X          }
  289. X       else
  290. X          Setexits( A, PatP );
  291. X    }
  292. X}
  293. X
  294. Xint CmplPat( char *Pattern, WORD *CmplPattern)
  295. X{
  296. X   int i, strlen();
  297. X   void Rch(), Setexits();
  298. X
  299. X   Pat = Pattern;
  300. X   Aux = CmplPattern;
  301. X   PatP = 0;
  302. X   Patlen = strlen( Pat );
  303. X   Errflag = FALSE;
  304. X
  305. X   for ( i = 0; i <= Patlen; i++ )
  306. X      Aux[ i ] = 0;
  307. X   Rch();
  308. X   Setexits( Exp(0), 0 );
  309. X   return (!Errflag);
  310. X}
  311. END_OF_FILE
  312. if test 5837 -ne `wc -c <'PatMatch.c'`; then
  313.     echo shar: \"'PatMatch.c'\" unpacked with wrong size!
  314. fi
  315. # end of 'PatMatch.c'
  316. fi
  317. if test -f 'browser.doc' -a "${1}" != "-c" ; then 
  318.   echo shar: Will not clobber existing file \"'browser.doc'\"
  319. else
  320. echo shar: Extracting \"'browser.doc'\" \(12580 characters\)
  321. sed "s/^X//" >'browser.doc' <<'END_OF_FILE'
  322. XBrowser -- a programmer's "Workbench". Release 1.7
  323. X
  324. X) 1990 Peter da Silva
  325. X
  326. XIntroduction
  327. X
  328. X    In earlier versions of Browser, I opened this document with the
  329. Xsomewhat confident comment:
  330. X
  331. X    The Amiga "Workbench" has some serious deficiencies as
  332. X    a working environment. The most important one is that
  333. X    it doesn't let you operate on just any file (this is
  334. X    rumored to be fixed in 1.4, by the way), but there are
  335. X    others. It's designed to be easy to learn and use, but
  336. X    it just isn't very powerful.
  337. X
  338. XWell, 1.4 is now 2.0, and it's almost here. So this is probably going to
  339. Xbe the last revision of Browser. I'm now using Workbench 2.0 on a daily
  340. Xbasis, and I find I'm not using Browser that much. It remains faster than
  341. Xworkbench and cleaner for quick jobs, but not enough for me to spend much
  342. Xtime on it. However, lots of people remain in a 1.3 environment, and with
  343. Xthe new release of the Aztec C compiler (5.0d) I've been able to clear up
  344. Xseveral outstanding bugs in Browser. Thus, the new release.
  345. X
  346. X    This program is an attempt to deal with limitations in earlier
  347. Xversions of the Workbench. It runs under all versions of AmigaOS, including
  348. X2.0, but is expected to be most useful for people running 1.3 and earlier.
  349. XIt is not a complete replacement for Workbench, nor is it intended to be.
  350. XThere is no attempt to support icons, and there are no disk-oriented
  351. Xfunctions (formatting, copying, etc...).
  352. X
  353. X    What Browser does allow you to do, easily and conveniently, is to
  354. Xmove, copy, rename, and delete files and directories. It will also let you
  355. Xexecute either Workbench or CLI programs, either directly by double-
  356. Xclicking them or by selecting them from a menu. By combining these you can
  357. Xset up a complete operating environment that will, to a large extent,
  358. Xreplace both Workbench and the CLI.
  359. X
  360. X    Browser presents you with a set of windows, representing directories,
  361. Xwith all the files and directories within each listed in alphabetical
  362. Xorder. Directories, displayed in color 2 (red/orange), are listed first,
  363. Xfollowed by the files. Selected files are displayed in inverse video.
  364. X
  365. XSelecting Files
  366. X
  367. X    You can select individual files three ways. First, just click on
  368. Xa file name. This will select that file and deselect all others. If you
  369. Xhold down the shift key when you click on the file, it will be selected
  370. Xwithout deselecting other files. This way you can build a list of files
  371. Xto operate on. So far this is just like Workbench, but if you click a
  372. Xselected file while holding down the shift key, it will be deselected
  373. Xwithout affecting other selected files. This lets you take back mistakes.
  374. X
  375. X    Finally, you can use the menu items "Sel All" and "Sel Match" to
  376. Xselect a group of files at once. "Sel All" will select all files in the
  377. Xactive window. "Sel Match" will allow you to enter a pattern and then
  378. Xselect only files matching that pattern in the active window. These
  379. Xnormally act as toggles... if you have any selected files in the active
  380. Xwindow they will be deselected if they match.
  381. X
  382. XActions
  383. X
  384. X    There are, again, three ways to manipulate selected files. First,
  385. Xyou can drag a file or selected files to another window by holding down the
  386. Xleft mouse button while you move the mouse. When you release the button,
  387. XBrowser will attempt to move the files to the location you indicate. This
  388. Xis just like the Workbench.
  389. X
  390. X    Secondly, double-clicking a file will open it. If it's a directory,
  391. Xit will be opened and files in it will be displayed. If it's a program
  392. Xwith an accompanying '.info' file, it will be launched as a Workbench task.
  393. XThis will also work with Projects, if the accompanying .info file specifies
  394. Xa tool. Finally, Browser will ask you if you want to launch it as a CLI
  395. Xprogram.
  396. X
  397. X    Any other files selected will be passed to the new program, either
  398. Xon the CLI command line or in the Workbench Args structure. This is the
  399. Xnormal Workbench shift-double-click method.
  400. X
  401. X    Third, you can select a menu item.
  402. X
  403. XMenus
  404. X
  405. X    There are two main Browser menus. The first, "Browser", relates to
  406. Xthe browser environment itself. The second, "Actions", relates to the files
  407. Xand directories displayed in Browser's windows. Menu items act either on
  408. Xselected files or on the currently active window. There are additional
  409. Xmenus (called Tools Menus) that can be set up by the user.
  410. X
  411. XBrowser Menu
  412. X
  413. X    Open
  414. X
  415. X        This entry is equivalent to double-clicking the selected
  416. X    file. It is included for consistency with Workbench. Strictly
  417. X    speaking it should be in the Actions menu, but it seems to fit
  418. X    here better.
  419. X
  420. X    Close
  421. X
  422. X        This entry is equivalent to clicking the active window's
  423. X    close gadget.  Again, it's included for consistency with the
  424. X    Workbench.
  425. X
  426. X    Rescan
  427. X
  428. X        This entry requests Browser to re-scan the directory displayed
  429. X    in the active window. This is equivalent to, but a lot more convenient
  430. X    than, closing and re-opening the window. I suppose I could poll the
  431. X    disk for these, but if you use floppies much this becomes slightly
  432. X    inconvenient.
  433. X
  434. X    Show >
  435. X
  436. X        This entry selects whether files, files and sizes, or full
  437. X    file information is displayed for the current window. It has been
  438. X    extended since 1.6a and is now provides a full set of options.
  439. X
  440. X    Sel All
  441. X
  442. X        This selects all files in the active window. Actually, it
  443. X    toggles the selection of each file. Currently selected files will
  444. X    be deselected.
  445. X
  446. X    Sel Match...
  447. X
  448. X        This is the same as Sel All, except that a pattern may be
  449. X    provided to further restrict the selection.
  450. X
  451. X    Options
  452. X
  453. X        This allows you to modify the global behaviour of Browser
  454. X    to some extent:
  455. X
  456. X        X Toggle Selections
  457. X
  458. X            This affects whether a selection through the menu,
  459. X        or a shift-click, will deselect an already selected file.
  460. X
  461. X        X Move files into subdirectories
  462. X
  463. X            This effects whether you can move files into a
  464. X        subdirectory by dragging them to it and releasing the mouse
  465. X        button when the mouse is over the directory's name. If this
  466. X        is not set you have to open the directory first.
  467. X
  468. X        X Ask before moving into subdirectories
  469. X
  470. X            If you permit files to be moved into subdirectories,
  471. X        this determines if Browser will prompt you beforehand.
  472. X
  473. X    Quit
  474. X
  475. X        This selection closes all windows and terminates Browser.
  476. X
  477. XActions Menu
  478. X
  479. X    The entries in this menu act on files rather than changing the state
  480. Xof Browser.
  481. X
  482. X    WB Tool
  483. X
  484. X        The currently selected file (singular) is entered into the
  485. X    Tools menu as a workbench tool.
  486. X
  487. X    CLI Tool...
  488. X
  489. X        The currently selected file (singular) is entered into the
  490. X    Tools menu as a CLI tool. Browser will pop up a requestor and allow
  491. X    you to add additional arguments.
  492. X
  493. X    Rename...
  494. X
  495. X        The currently selected file (singular) is renamed. Browser
  496. X    will pop up a requestor and allow you to enter the new name.
  497. X
  498. X    Duplicate...
  499. X
  500. X        The currently selected file (singular) is duplicated. Browser
  501. X    will pop up a requestor and allow you to edit the new name (generated
  502. X    by BumpRevision: "file" becomes "copy of file", and so on).
  503. X
  504. X    Make Dir...
  505. X
  506. X        Creates a new directory in the currently active window.
  507. X    Browser will pop up a requestor and allow you to specify the name of
  508. X    the new directory.
  509. X
  510. X    Delete
  511. X
  512. X        Deletes all selected files. This will only delete directories
  513. X    if they happen to be empty.
  514. X
  515. X    Delete All
  516. X
  517. X        Deletes all selected files AND directories, recursively.
  518. X
  519. XTools Menus
  520. X
  521. X    These menus (starting with Tools) are initially empty. They are filled
  522. Xin by selecting "Add * Tool" or from the file "s:browser.inittab". When you
  523. Xselect an entry in these menus they're run (either as workbench or CLI
  524. Xprograms) with all selected files being passed to the program. If you have
  525. Xa choice, you should make a program run under the Workbench... it's MUCH
  526. Xmore reliable.
  527. X
  528. XEnvironment
  529. X
  530. X    Browser can itself be run from either the Workbench or the CLI. The
  531. Xseparate "bgbrowser" program no longer exists... use "runback" or some
  532. Xequivalent program if you want to run browser in a detached mode.
  533. X
  534. X    Browser uses a file, "s:browser.inittab", to pre-load the command
  535. Xmenus. Each line in the file is a separate menu item, made up of 5 fields
  536. Xseparated by semicolons:
  537. X
  538. X    name;environment;command;stack;window
  539. X
  540. X    The first field is the name that is to appear in the menu. This
  541. Xname can be preceded by the name of the menu to insert it in followed by
  542. Xa period. If the menu name is left off, the "Tools" menu will be used.
  543. XFor example, "Applications.Terminal Emulator" will create a menu entry
  544. Xfor "Terminal Emulator" and install it in the "Applications" menu. If the
  545. Xmenu doesn't already exist, it will be created.
  546. X
  547. X    The two environments currently supported are the CLI and the
  548. XWorkbench. Project files (such as AmigaBasic programs) aren't supported
  549. Xthrough the menu system at this time, though they may be at a later date.
  550. XThey do work just fine when you double-click them.
  551. X
  552. X    If our terminal emulator was to be run as a Workbench program, then
  553. Xthis field should contain "Workbench". If it can't run under the Workbench,
  554. Xthen it should contain "CLI". It is better, if possible, to run programs
  555. Xunder the Workbench. It's a cleaner environment, and you don't get extra
  556. Xwindows cluttering up your display.
  557. X
  558. X    The next field is the name of the command. This should contain the
  559. Xfull path name to the program. If the command is a CLI command, additional
  560. Xarguments can be included at this point. The names of any files highlighted
  561. Xwhen this menu is selected will be added to the end. If the command is
  562. Xa Workbench command, this should just be the program name. Highlighted
  563. Xfiles will be passed to the program in the Workbench Args structure.
  564. X
  565. X    The next field is the stack size. It may be left off, and will
  566. Xdefault to 8K.
  567. X
  568. X    The last field is the window. For a CLI command, this is the
  569. Xwindow that will be opened to run the CLI in. For a Workbench command,
  570. Xthis is the ToolWindow that will be passed to it. If it's left off a
  571. Xdefault will be used.
  572. X
  573. X    Applications.Terminal Emulator;Workbench;sys:system/Termulator
  574. X
  575. XLimitations:
  576. X
  577. X    The CLI capability occasionally leaves you in an interactive CLI
  578. Xafter you exit the program. This is caused by using one of the BREAK keys
  579. Xwhile you're in the program. I had to leave this in to get finicky CLI
  580. Xprograms, such as Manx 'Z' editor, to work properly.
  581. X
  582. X    If you're copying a file to disk and you get a disk error,
  583. Xoccasionally browser will appear to ignore disk errors and keep on trying
  584. Xto write. Actually, Browser handles all disk errors that get reported to
  585. Xit. For some reason AmigaDOS doesn't report errors promptly. I suspect
  586. Xthis is related to requesting writes larger than a disk buffer, but I
  587. Xdon't plan on having Browser do anything about this in the near future.
  588. X
  589. X    Browser seems to run just fine with only the standard 4K stack. The
  590. Xminimum environment you need to run browser is:
  591. X
  592. X     libs (dir)
  593. X       icon.library
  594. X
  595. XIf you also want to run CLI programs, you also need:
  596. X
  597. X     c (dir)
  598. X       cd                               EndCLI
  599. X       Failat                           NewCLI
  600. X       Run                              Stack
  601. X     l (dir)
  602. X       Ram-Handler
  603. X
  604. XThese are needed to run the little scripts Browser builds in RAM: when you
  605. Xrun a CLI program.
  606. X
  607. XAuthor:
  608. X
  609. X    Peter da Silva
  610. X
  611. X    U.S.Mail:
  612. X        15770 Bellaire Blvd. #107
  613. X        Houston, TX  77083
  614. X
  615. X    Phone:
  616. X        +1 713 568 0480    (data: Taronga Park)
  617. X        +1 713 274 5180 (work)
  618. X
  619. X    Internet:
  620. X        peter@taronga.hackercorp.com
  621. X    Compuserve:
  622. X        >internet:peter@taronga.hackercorp.com (preferred)
  623. X        70216,1076
  624. X
  625. X    I'm currently getting a new domain name, so if your mail to
  626. Xtaronga.hackercorp.com bounces or is delayed, try taronga.com. If all
  627. Xelse fails I'm currently working at Ferranti International Controls
  628. XCorporation, so try peter@ferranti.com.
  629. X
  630. XDonations:
  631. X
  632. X    If you find this program useful, you may send a donation to the
  633. Xauthor, Peter da Silva. For a donation of thirty dollars or more you will
  634. Xreceive the latest version of Browser (or, if you prefer, the next version
  635. Xif it ever comes out... as I said, 1.7 is likely to be the ultimate release).
  636. X
  637. X    If you have been waiting for the next release and it hasn't got
  638. Xto you, call me or send me email. With this release I'm sending all the
  639. Xfolks who contributed the program and a copy of the source. You should get
  640. Xa copy in the mail soon.
  641. X
  642. XSponsors:
  643. X
  644. X    The following people have donated money, and are willing to have
  645. Xtheir names up in lights. Thanks, folks. In no particular order...
  646. X
  647. X    <CB>
  648. X    Kent and Judy Polk
  649. X    Burkard S. Kr|ger
  650. X    D. Ballinger
  651. X    Ron Harper
  652. X    Steven D. Kapplin
  653. X    David Allen
  654. X    Glen Fullmer
  655. X    Ed Vishoot
  656. X    Jeff Van Epps
  657. X    P. Wright
  658. X    Heinz Mathalm
  659. X    Blaine Gardner
  660. X    Liam Healy
  661. X    Johan Widin
  662. X    D. Ratliff
  663. X    T. J. Pagano
  664. X    J|rgen Klawitter
  665. X    Ulrich Denker
  666. X    Rick Jones
  667. X    Guenther Engelhardt
  668. X
  669. XAnd special thanks to my wife, Stephanie, who talked me into doing this
  670. Xrelease.
  671. END_OF_FILE
  672. if test 12580 -ne `wc -c <'browser.doc'`; then
  673.     echo shar: \"'browser.doc'\" unpacked with wrong size!
  674. fi
  675. # end of 'browser.doc'
  676. fi
  677. if test -f 'fonts.h' -a "${1}" != "-c" ; then 
  678.   echo shar: Will not clobber existing file \"'fonts.h'\"
  679. else
  680. echo shar: Extracting \"'fonts.h'\" \(355 characters\)
  681. sed "s/^X//" >'fonts.h' <<'END_OF_FILE'
  682. X#ifndef FONTS_H
  683. X#define FONTS_H
  684. X#ifndef GRAPHICS_GFXBASE_H
  685. X#include <graphics/gfxbase.h>
  686. X#endif
  687. X#ifndef GRAPHICS_TEXT_H
  688. X#include <graphics/text.h>
  689. X#endif
  690. X
  691. Xextern struct GfxBase *GfxBase;
  692. X
  693. X#define FONTWIDTH (GfxBase->DefaultFont->tf_XSize)
  694. X#define FONTHEIGHT (GfxBase->DefaultFont->tf_YSize)
  695. X#define FONTBASELINE (GfxBase->DefaultFont->tf_Baseline)
  696. X#endif
  697. END_OF_FILE
  698. if test 355 -ne `wc -c <'fonts.h'`; then
  699.     echo shar: \"'fonts.h'\" unpacked with wrong size!
  700. fi
  701. # end of 'fonts.h'
  702. fi
  703. if test -f 'goodies.readme' -a "${1}" != "-c" ; then 
  704.   echo shar: Will not clobber existing file \"'goodies.readme'\"
  705. else
  706. echo shar: Extracting \"'goodies.readme'\" \(451 characters\)
  707. sed "s/^X//" >'goodies.readme' <<'END_OF_FILE'
  708. XThe 'goodies' are sections of the source to Browser that I have previously
  709. Xreleased into the public domain, or that I got from the public domain. I
  710. Xfigure that you folks should benefit from them:
  711. X
  712. X    PatMatch.c    A very nice AmigaDOS-compatible regular expression parser.
  713. X    menu.c    A fairly clean way of dealing with lots of silly menus.
  714. X        menu.h    Needed for menu.c
  715. X        fonts.h    Needed for menu.c
  716. X    vollist.c    An Examine/ExNext type interface to the device list.
  717. END_OF_FILE
  718. if test 451 -ne `wc -c <'goodies.readme'`; then
  719.     echo shar: \"'goodies.readme'\" unpacked with wrong size!
  720. fi
  721. # end of 'goodies.readme'
  722. fi
  723. if test -f 'menu.c' -a "${1}" != "-c" ; then 
  724.   echo shar: Will not clobber existing file \"'menu.c'\"
  725. else
  726. echo shar: Extracting \"'menu.c'\" \(8280 characters\)
  727. sed "s/^X//" >'menu.c' <<'END_OF_FILE'
  728. X/* easy menus: Copyright 1987 Peter da Silva, all rights reserved.
  729. X *
  730. X *    Permission is granted to use this in any application, so long as
  731. X *    this notice is retained in the source. Permission is granted to
  732. X *    modify the code as you like, so long as this notice (between the
  733. X *    first line beginning "easy menus" and the end of this paragraph,
  734. X *    inclusive) is retained intact.
  735. X *
  736. X * Usage:
  737. X *
  738. X *    #include "menu.h"
  739. X *
  740. X *    struct MenuPtr menudata;
  741. X *    struct MenuPtr *menuptr = &menudata;
  742. X *
  743. X *    init_menus(menuptr);    / * Just zero menu pointer out * /
  744. X *
  745. X *    for(each menu item) {
  746. X *        add_menu(menuptr, menu, item, subitem, flags);
  747. X *    }
  748. X *
  749. X *  Flags:
  750. X *    SUBITEM_NOCHECK    -- subitem does not require a checkmark.
  751. X *    SUBITEM_SELECTOR    -- subitem is a 1 of n selector, use mutual-exclude.
  752. X *    SUBITEM_TOGGLE    -- subitem is a toggled flag.
  753. X *    SUBITEM_SELECTED    -- defaults to checked.
  754. X *
  755. X *
  756. X *    SetMenuStrip(yourwindow, menuptr->MenuBar);
  757. X *
  758. X *    ...
  759. X *
  760. X *    ClearMenuStrip(yourwindow);
  761. X *
  762. X *    trash_menus(menuptr);
  763. X *
  764. X * Notes:
  765. X *
  766. X *    if you don't want any subitems, use zero for the subitem value.
  767. X *
  768. X *    subitem is always initialised as a CHECKIT item with all the other
  769. X *    subitems mutually excluded.
  770. X *
  771. X *    it is intended that the menu be set up with all action items in
  772. X *    the first level of the menu, and all toggles in the second level...
  773. X *    this is a piece of blatant authoritarianism on my part. I've seen
  774. X *    too many menus with no rhyme or reason. Look at AmigaTerm (the term
  775. X *    program that comes with the Amiga modem) some time. Baud rate has
  776. X *    an item all by itself, but word size is hidden off in a menu with
  777. X *    things like bell sound.
  778. X *
  779. X *    the appearance of the menus produced by this is (in my humble
  780. X *    opinion) good. I took some care making text centered in menu boxes,
  781. X *    for example.
  782. X */
  783. X#include <exec/memory.h>
  784. X#include <intuition/intuition.h>
  785. X#include "menu.h"
  786. X#include "fonts.h"
  787. X
  788. X/* Forward prototypes */
  789. Xstatic void nudge(struct MenuItem *item, int delta);
  790. Xstatic struct Menu *
  791. X    new_menu(struct MenuPtr *menuptr, char *name);
  792. Xstatic struct MenuItem *
  793. X    new_item(struct MenuPtr *menuptr,
  794. X        struct Menu *menu, UBYTE *name);
  795. Xstatic struct MenuItem *
  796. X    new_subitem(struct MenuPtr *menuptr,
  797. X        struct MenuItem *item, UBYTE *name, long flags);
  798. X
  799. X/*
  800. Xstruct MenuPtr {
  801. X    struct Menu *MenuBar;
  802. X    struct Remember *MenuMemory;
  803. X};
  804. X*/
  805. X
  806. Xchar *AllocRemember();
  807. X
  808. Xstatic struct Menu *new_menu();
  809. Xstatic struct MenuItem *new_item(), *new_subitem();
  810. X
  811. X#define TOMENUNUM(i,j,k) (SHIFTMENU(i)|SHIFTITEM(j)|SHIFTSUB(k))
  812. X#define TextLen(s) (strlen(s)*FONTWIDTH)
  813. X
  814. Xvoid trash_menus(struct MenuPtr *menuptr)
  815. X{
  816. X    FreeRemember(&menuptr->MenuMemory, 1);
  817. X    menuptr->MenuMemory = 0;
  818. X    menuptr->MenuBar = 0;
  819. X}
  820. X
  821. Xvoid init_menus(struct MenuPtr *menuptr)
  822. X{
  823. X    menuptr->MenuMemory = 0;
  824. X    menuptr->MenuBar = 0;
  825. X}
  826. X
  827. Xint add_menu(
  828. X    struct MenuPtr *menuptr,
  829. X    char *menuname,
  830. X    char *itemname,
  831. X    char *subitemname,
  832. X    long flags)
  833. X{
  834. X    int i, j, k;
  835. X    struct Menu *menu;
  836. X    struct MenuItem *item;
  837. X    struct MenuItem *subitem;
  838. X
  839. X    if(menuptr->MenuBar) {
  840. X        for(i = 0, menu = menuptr->MenuBar;
  841. X            menu;
  842. X            menu = menu->NextMenu, i++
  843. X           )
  844. X            if(strcmp(menuname, menu->MenuName)==0)
  845. X                break;
  846. X        if(!menu)
  847. X            menu = new_menu(menuptr, menuname);
  848. X        if(!menu)
  849. X            return MENUNULL;
  850. X    } else {
  851. X        i = 0;
  852. X        menu = new_menu(menuptr, menuname);
  853. X        if(!menu)
  854. X            return MENUNULL;
  855. X    }
  856. X    for(j = 0, item = menu->FirstItem;
  857. X        item;
  858. X        item = item->NextItem, j++
  859. X       ) {
  860. X        struct IntuiText *text;
  861. X        text = (struct IntuiText *)item->ItemFill;
  862. X        if(strcmp(itemname, text->IText) == 0)
  863. X            break;
  864. X    }
  865. X    if(subitemname) {
  866. X        if(!item)
  867. X            item = new_item(menuptr, menu, (UBYTE *)itemname);
  868. X        if(!item)
  869. X            return MENUNULL;
  870. X        for(k = 0, subitem = item->SubItem;
  871. X            subitem;
  872. X            subitem = subitem->NextItem, k++
  873. X           ) {
  874. X            struct IntuiText *text;
  875. X            text = (struct IntuiText *)subitem->ItemFill;
  876. X            if(strcmp(subitemname, text->IText) == 0)
  877. X                break;
  878. X        }
  879. X        if(!subitem)
  880. X            subitem = new_subitem(menuptr, item, (UBYTE *)subitemname, flags);
  881. X        if(!subitem)
  882. X            return MENUNULL;
  883. X        return TOMENUNUM(i, j, k);
  884. X    } else {
  885. X        if(!item)
  886. X            item = new_item(menuptr, menu, (UBYTE *)itemname);
  887. X        if(!item)
  888. X            return MENUNULL;
  889. X        return TOMENUNUM(i, j, NOSUB);
  890. X    }
  891. X}
  892. X
  893. Xstatic struct Menu *
  894. Xnew_menu(struct MenuPtr *menuptr, char *name)
  895. X{
  896. X    struct Menu *menu;
  897. X
  898. X    menu = (struct Menu *)AllocRemember(
  899. X        &menuptr->MenuMemory,
  900. X        sizeof(struct Menu),
  901. X        MEMF_PUBLIC);
  902. X    if(!menu)
  903. X        return 0;
  904. X    menu->NextMenu = NULL;
  905. X    menu->LeftEdge = 0;
  906. X    menu->TopEdge = 0;
  907. X    menu->Width = TextLen(name)+FONTWIDTH;
  908. X    menu->Height = 0;
  909. X    menu->Flags = MENUENABLED;
  910. X    menu->MenuName = name;
  911. X    menu->FirstItem = 0;
  912. X    if(menuptr->MenuBar) {
  913. X        struct Menu *ptr, *prev;
  914. X        for(ptr = menuptr->MenuBar; ptr; ptr=ptr->NextMenu) {
  915. X            menu->LeftEdge += ptr->Width;
  916. X            prev = ptr;
  917. X        }
  918. X        prev->NextMenu = menu;
  919. X    } else {
  920. X        menuptr->MenuBar = menu;
  921. X    }
  922. X
  923. X    return menu;
  924. X}
  925. X
  926. Xstatic struct MenuItem *
  927. Xnew_item(struct MenuPtr *menuptr, struct Menu *menu, UBYTE *name)
  928. X{
  929. X    struct MenuItem *item;
  930. X    struct IntuiText *text;
  931. X
  932. X    item = (struct MenuItem *)AllocRemember(
  933. X        &menuptr->MenuMemory,
  934. X        sizeof(struct MenuItem),
  935. X        MEMF_PUBLIC);
  936. X    if(!item)
  937. X        return 0;
  938. X    text = (struct IntuiText *)AllocRemember(
  939. X        &menuptr->MenuMemory,
  940. X        sizeof(struct IntuiText),
  941. X        MEMF_PUBLIC);
  942. X    if(!text)
  943. X        return 0;
  944. X
  945. X    text->FrontPen = AUTOFRONTPEN;
  946. X    text->BackPen = AUTOBACKPEN;
  947. X    text->DrawMode = JAM2;
  948. X    text->LeftEdge = 1;
  949. X    text->TopEdge = 1;
  950. X    text->ITextFont = NULL;
  951. X    text->IText = name;
  952. X    text->NextText = NULL;
  953. X
  954. X    item->NextItem = NULL;
  955. X    item->LeftEdge = 0;
  956. X    item->TopEdge = 0;
  957. X    item->Width = IntuiTextLength(text)+2;
  958. X    if(item->Width <= menu->Width)
  959. X        item->Width = menu->Width+1;
  960. X    item->Height = FONTHEIGHT+1;
  961. X    item->Flags = ITEMTEXT|HIGHCOMP|ITEMENABLED;
  962. X    item->MutualExclude = 0;
  963. X    item->ItemFill = (APTR)text;
  964. X    item->SelectFill = NULL;
  965. X    item->Command = 0;
  966. X    item->SubItem = NULL;
  967. X    item->NextSelect = NULL;
  968. X
  969. X    if(menu->FirstItem) {
  970. X        struct MenuItem *ptr, *prev;
  971. X        for(ptr = menu->FirstItem; ptr; ptr=ptr->NextItem) {
  972. X            if(item->Width > ptr->Width) {
  973. X                if(ptr->SubItem)
  974. X                    nudge(ptr->SubItem, item->Width-ptr->Width);
  975. X                ptr->Width = item->Width;
  976. X            } else if(ptr->Width>item->Width)
  977. X                item->Width = ptr->Width;
  978. X            prev = ptr;
  979. X        }
  980. X        item->TopEdge = prev->TopEdge + prev->Height;
  981. X        prev->NextItem = item;
  982. X    } else {
  983. X        menu->FirstItem = item;
  984. X    }
  985. X
  986. X    return item;
  987. X}
  988. X
  989. Xstatic void nudge(struct MenuItem *item, int delta)
  990. X{
  991. X    while(item) {
  992. X        item->LeftEdge += delta;
  993. X        item = item->NextItem;
  994. X    }
  995. X}
  996. X
  997. Xstatic struct MenuItem *
  998. Xnew_subitem(
  999. X    struct MenuPtr *menuptr,
  1000. X    struct MenuItem *item,
  1001. X    UBYTE *name,
  1002. X    long flags)
  1003. X{
  1004. X    struct MenuItem *subitem;
  1005. X    struct IntuiText *text;
  1006. X
  1007. X    subitem = (struct MenuItem *)AllocRemember(
  1008. X        &menuptr->MenuMemory,
  1009. X        sizeof(struct MenuItem),
  1010. X        MEMF_PUBLIC);
  1011. X    if(!subitem)
  1012. X        return 0;
  1013. X    text = (struct IntuiText *)AllocRemember(
  1014. X        &menuptr->MenuMemory,
  1015. X        sizeof(struct IntuiText),
  1016. X        MEMF_PUBLIC);
  1017. X    if(!text)
  1018. X        return 0;
  1019. X
  1020. X    text->FrontPen = AUTOFRONTPEN;
  1021. X    text->BackPen = AUTOBACKPEN;
  1022. X    text->DrawMode = JAM2;
  1023. X    text->LeftEdge = 1;
  1024. X    if(flags != SUBITEM_NOCHECK) text->LeftEdge += CHECKWIDTH;
  1025. X    text->TopEdge = 1;
  1026. X    text->ITextFont = NULL;
  1027. X    text->IText = name;
  1028. X    text->NextText = NULL;
  1029. X
  1030. X    subitem->NextItem = NULL;
  1031. X    subitem->LeftEdge = item->Width;
  1032. X    subitem->TopEdge = 0;
  1033. X    subitem->Width = IntuiTextLength(text)+2;
  1034. X    if(flags != SUBITEM_NOCHECK) subitem->Width += CHECKWIDTH;
  1035. X    subitem->Height = FONTHEIGHT+1;
  1036. X    subitem->Flags = ITEMTEXT|ITEMENABLED|HIGHCOMP;
  1037. X    subitem->MutualExclude = 0;
  1038. X    if(flags != SUBITEM_NOCHECK) {
  1039. X        subitem->Flags |= CHECKIT;
  1040. X        if(flags & SUBITEM_TOGGLE) subitem->Flags |= MENUTOGGLE;
  1041. X        if(flags & SUBITEM_SELECTED) subitem->Flags |= CHECKED;
  1042. X    }
  1043. X    subitem->ItemFill = (APTR)text;
  1044. X    subitem->SelectFill = NULL;
  1045. X    subitem->Command = 0;
  1046. X    subitem->SubItem = NULL;
  1047. X    subitem->NextSelect = NULL;
  1048. X
  1049. X    if(item->SubItem) {
  1050. X        struct MenuItem *ptr, *prev;
  1051. X        int i;
  1052. X        for(i=0, ptr = item->SubItem; ptr; i++, ptr=ptr->NextItem) {
  1053. X            if(subitem->Width > ptr->Width)
  1054. X                ptr->Width = subitem->Width;
  1055. X            else if(ptr->Width>subitem->Width)
  1056. X                subitem->Width = ptr->Width;
  1057. X            prev = ptr;
  1058. X        }
  1059. X        subitem->TopEdge = prev->TopEdge + prev->Height;
  1060. X        if(flags & SUBITEM_SELECTOR)
  1061. X            subitem->MutualExclude = ~(1<<i);
  1062. X        prev->NextItem = subitem;
  1063. X    } else {
  1064. X        item->SubItem = subitem;
  1065. X        if(flags & SUBITEM_SELECTOR)
  1066. X            subitem->MutualExclude = ~1;
  1067. X    }
  1068. X
  1069. X    return subitem;
  1070. X}
  1071. END_OF_FILE
  1072. if test 8280 -ne `wc -c <'menu.c'`; then
  1073.     echo shar: \"'menu.c'\" unpacked with wrong size!
  1074. fi
  1075. # end of 'menu.c'
  1076. fi
  1077. if test -f 'menu.h' -a "${1}" != "-c" ; then 
  1078.   echo shar: Will not clobber existing file \"'menu.h'\"
  1079. else
  1080. echo shar: Extracting \"'menu.h'\" \(359 characters\)
  1081. sed "s/^X//" >'menu.h' <<'END_OF_FILE'
  1082. Xstruct MenuPtr {
  1083. X    struct Menu *MenuBar;
  1084. X    struct Remember *MenuMemory;
  1085. X    int next_id;
  1086. X};
  1087. X
  1088. X/* flags */
  1089. X#define SUBITEM_NOCHECK     0x0     /* subitem does not require a checkmark. */
  1090. X#define SUBITEM_SELECTOR    0x10    /* subitem is a 1 of n selector */
  1091. X#define SUBITEM_TOGGLE      0x20    /* subitem is a toggled flag. */
  1092. X#define SUBITEM_SELECTED    0x01    /* defaults to checked. */
  1093. END_OF_FILE
  1094. if test 359 -ne `wc -c <'menu.h'`; then
  1095.     echo shar: \"'menu.h'\" unpacked with wrong size!
  1096. fi
  1097. # end of 'menu.h'
  1098. fi
  1099. if test -f 'vollist.c' -a "${1}" != "-c" ; then 
  1100.   echo shar: Will not clobber existing file \"'vollist.c'\"
  1101. else
  1102. echo shar: Extracting \"'vollist.c'\" \(1578 characters\)
  1103. sed "s/^X//" >'vollist.c' <<'END_OF_FILE'
  1104. X#include <libraries/dosextens.h>
  1105. X#include <stdio.h>
  1106. X#ifdef DEBUG
  1107. X#include "debug.h"
  1108. X#endif
  1109. X/* Fakes an Examine/ExNext interface to the device list. Call OpenVolList
  1110. X * first, then ReadVolList(fib), and finally CloseVolList. This last is
  1111. X * a dummy, but it's handy if you want to be safe and put a forbid/permit
  1112. X * around the whole thing.
  1113. X */
  1114. X
  1115. X#define toAPTR(b) ((b)<<2)
  1116. X#define toBPTR(a) ((a)>>2)
  1117. X
  1118. Xstruct DeviceList *list;
  1119. X
  1120. Xvoid OpenVolList(void)
  1121. X{
  1122. X    extern struct DosLibrary *DOSBase;
  1123. X    struct RootNode *root;
  1124. X    struct DosInfo *info;
  1125. X
  1126. X    root = (struct RootNode *)DOSBase -> dl_Root;
  1127. X    info = (struct DosInfo *)toAPTR(root->rn_Info);
  1128. X    list = (struct DeviceList *)toAPTR(info->di_DevInfo);
  1129. X}
  1130. X
  1131. Xint ReadVolList(struct FileInfoBlock *fib)
  1132. X{
  1133. X    struct DeviceList *next;
  1134. X
  1135. X    while(list) {
  1136. X        next = (struct DeviceList *)toAPTR(list->dl_Next);
  1137. X        if(list->dl_Type == DLT_VOLUME ||
  1138. X           list->dl_Type == DLT_DIRECTORY) {
  1139. X            char *ptr;
  1140. X            int count;
  1141. X            ptr = (char *)toAPTR((BPTR)list->dl_Name);
  1142. X            count = *ptr++;
  1143. X            if(count > 106)
  1144. X                count = 106;
  1145. X            strncpy(fib->fib_FileName, ptr, count);
  1146. X            fib->fib_FileName[count++] = ':';
  1147. X            fib->fib_FileName[count] = 0;
  1148. X            if(strcmp(fib->fib_FileName, "RAM Disk:") == 0)
  1149. X                strcpy(fib->fib_FileName, "RAM:");
  1150. X            fib->fib_DiskKey = 0;
  1151. X            fib->fib_DirEntryType = list->dl_Type;
  1152. X            fib->fib_Protection = 0;
  1153. X            fib->fib_EntryType = list->dl_Type;
  1154. X            fib->fib_Size = 0;
  1155. X            fib->fib_NumBlocks = 0;
  1156. X            fib->fib_Date = list->dl_VolumeDate;
  1157. X            fib->fib_Comment[0] = 0;
  1158. X            list = next;
  1159. X            return 1;
  1160. X        }
  1161. X        list = next;
  1162. X    }
  1163. X    return 0;
  1164. X}
  1165. X
  1166. Xvoid CloseVolList(void)
  1167. X{
  1168. X}
  1169. END_OF_FILE
  1170. if test 1578 -ne `wc -c <'vollist.c'`; then
  1171.     echo shar: \"'vollist.c'\" unpacked with wrong size!
  1172. fi
  1173. # end of 'vollist.c'
  1174. fi
  1175. echo shar: End of archive 1 \(of 1\).
  1176. cp /dev/null ark1isdone
  1177. MISSING=""
  1178. for I in 1 ; do
  1179.     if test ! -f ark${I}isdone ; then
  1180.     MISSING="${MISSING} ${I}"
  1181.     fi
  1182. done
  1183. if test "${MISSING}" = "" ; then
  1184.     echo You have the archive.
  1185.     rm -f ark[1-9]isdone
  1186. else
  1187.     echo You still need to unpack the following archives:
  1188.     echo "        " ${MISSING}
  1189. fi
  1190. ##  End of shell archive.
  1191. exit 0
  1192. -- 
  1193. Mail submissions (sources or binaries) to <amiga@uunet.uu.net>.
  1194. Mail comments to the moderator at <amiga-request@uunet.uu.net>.
  1195. Post requests for sources, and general discussion to comp.sys.amiga.misc.
  1196.